﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Engine.Sgml.Schema;
using System.Xml.Linq;
using System.Xml.XPath;

namespace Engine.Sgml.Test {
    /// <summary>
    /// Summary description for SElementFixture
    /// </summary>
    [TestClass]
    public class SElementFixture {
        public SElementFixture() {
            //
            // TODO: Add constructor logic here
            //
            }

        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext {
            get {
                return testContextInstance;
                }
            set {
                testContextInstance = value;
                }
            }

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion

        [TestMethod]
        public void Add() {
            SgmlDocument doc = new SgmlDocument();
            SElement html = new SElement("html", SgmlNodeType.Element);
            SAttribute attrType = new SAttribute("type", "text");
            html.Add(attrType);
            Assert.IsNotNull(attrType.Parent);
            Assert.IsTrue(attrType.Parent == html);

            SAttribute attrName = new SAttribute("name", "button");
            html.Add(attrName);

            Assert.IsTrue(html.HasAttributes());
            Assert.IsNotNull(html.Attribute("type"));

            doc.Root.Add(html);
            Assert.IsNotNull(html.Parent);
            Assert.IsTrue(html.Parent == doc.Root);
            Assert.IsTrue(doc.Root.HasElements());
            Assert.IsFalse(string.IsNullOrEmpty(doc.ToString()));

            string content = doc.ToString();
            string xml = doc.ToXml();
            }

        [TestMethod]
        public void AddFirst() {
            SgmlDocument doc = new SgmlDocument();

            SElement html = new SElement("html", SgmlNodeType.Element);
            doc.Root.Add(html);
            Assert.IsFalse(html.HasAttributes());
            Assert.IsFalse(html.HasDeclaration());

            SAttribute attr1 = new SAttribute("type", "1");
            SAttribute attr2 = new SAttribute("name", "2");

            html.Add(attr2);
            html.AddFirst(attr1);

            SElement doctype = new SElement("html", SgmlNodeType.DocumentType);
            doc.Root.AddFirst(doctype);

            Assert.IsTrue(doc.Root.FirstNode() == doctype);
            Assert.IsTrue(doctype.NextNode() == html);
            Assert.IsNull(doctype.PreviousNode());

            SElement head = new SElement("head", SgmlNodeType.Element);
            doc.Root.Add(head);

            string content = doc.ToString();
            string xml = doc.ToXml();
            }

        [TestMethod]
        public void AddAfterSelf() {
            SgmlDocument doc = new SgmlDocument();
            SElement html = new SElement("html", SgmlNodeType.Element);
            doc.Root.Add(html);

            SElement head = new SElement("head", SgmlNodeType.Element);
            SElement body = new SElement("body", SgmlNodeType.Element);

            InvalidOperationException ex = null;
            try {
                body.AddBeforeSelf(head);
                }
            catch (InvalidOperationException e) {
                ex = e;
                }
            Assert.IsNotNull(ex);

            html.Add(head);
            head.AddAfterSelf(body);

            Assert.IsTrue(head.NextNode() == body);
            Assert.IsTrue(body.PreviousNode() == head);

            Assert.IsNull(head.PreviousNode());
            Assert.IsNull(body.NextNode());

            string content = doc.ToString();
            string xml = doc.ToXml();
            }


        [TestMethod]
        public void AddBeforeSelf() {
            SgmlDocument doc = new SgmlDocument();
            SElement html = new SElement("html", SgmlNodeType.Element);
            doc.Root.Add(html);

            SElement head = new SElement("head", SgmlNodeType.Element);
            SElement body = new SElement("body", SgmlNodeType.Element);

            InvalidOperationException ex = null;
            try {
                body.AddBeforeSelf(head);
                }
            catch (InvalidOperationException e) {
                ex = e;
                }
            Assert.IsNotNull(ex);

            html.Add(body);
            body.AddBeforeSelf(head);

            Assert.IsTrue(head.NextNode() == body);
            Assert.IsTrue(body.PreviousNode() == head);

            Assert.IsNull(head.PreviousNode());
            Assert.IsNull(body.NextNode());

            string content = doc.ToString();
            string xml = doc.ToXml();
            }

        [TestMethod]
        public void Remove() {
            SgmlDocument doc = new SgmlDocument();
            SElement html = new SElement("html", SgmlNodeType.Element);
            doc.Root.Add(html);
            SAttribute attr1 = new SAttribute("type", "1");
            SAttribute attr2 = new SAttribute("name", "2");
            html.AddFirst(attr1);
            html.Add(attr2);

            attr1.Remove();
            Assert.IsNull(attr1.Parent);
            Assert.IsTrue(html.Attributes().Count() == 1);
            Assert.IsTrue(html.FirstAttribute() == attr2);

            html.Remove();
            Assert.IsNull(html.Parent);
            Assert.IsFalse(doc.Root.HasElements());
            }

        [TestMethod]
        public void Clone() {
            SgmlDocument doc = new SgmlDocument();
            SElement html = new SElement("html", SgmlNodeType.Element);
            doc.Root.Add(html);
            SAttribute attr1 = new SAttribute("type", "1");
            SAttribute attr2 = new SAttribute("name", "2");
            html.Add(attr1);
            html.Add(attr2);


            SElement clone = html.Clone();

            Assert.IsNull(clone.Parent);
            Assert.IsTrue(clone.HasAttributes());
            Assert.IsFalse(clone.HasElements());
            Assert.IsTrue(clone.Attributes().Count() == 2);
            Assert.IsTrue(clone.Prefix == html.Prefix);
            Assert.IsTrue(clone.LocalName == html.LocalName);
            Assert.IsTrue(clone.Value == html.Value);
            Assert.IsTrue(clone.Declaration == html.Declaration);
            Assert.IsTrue(clone.IsEmpty == html.IsEmpty);
            Assert.IsTrue(clone.LineNumber == 0);
            Assert.IsTrue(clone.LinePosition == 0);
            Assert.IsTrue(clone.NodeType == html.NodeType);
            Assert.IsTrue(clone.XPath() == html.XPath());

            SElement head = new SElement("head", SgmlNodeType.Element);
            html.Add(head);

            clone = html.Clone();
            Assert.IsFalse(clone.HasElements());

            clone = html.Clone(true);
            Assert.IsTrue(clone.HasElements());
            Assert.IsFalse(clone.FirstNode() == head);

            head.Remove();

            Assert.IsTrue(clone.HasElements());
            }

        [TestMethod]
        public void Navigation() {
            SgmlDocument doc = new SgmlDocument();
            SElement html = new SElement("html", SgmlNodeType.Element);

            Assert.IsNull(html.LastAttribute());
            Assert.IsNull(html.FirstAttribute());

            SAttribute attr1 = new SAttribute("attr1", "1");
            SAttribute attr2 = new SAttribute("attr2", "2");

            html.Add(attr1);
            html.Add(attr2);

            Assert.IsTrue(html.FirstAttribute() == attr1);
            Assert.IsNull(attr1.PreviousAttribute());
            Assert.IsNull(attr2.NextAttribute());
            Assert.IsTrue(attr1.NextAttribute() == attr2);
            Assert.IsTrue(attr2.PreviousAttribute() == attr1);
            Assert.IsTrue(html.LastAttribute() == attr2);

            SElement head = new SElement("head", SgmlNodeType.Element);
            SElement body = new SElement("body", SgmlNodeType.Element);

            Assert.IsNull(html.FirstNode());
            Assert.IsNull(html.LastNode());
            Assert.IsNull(html.PreviousNode());
            Assert.IsNull(html.NextNode());

            html.Add(head);
            html.Add(body);

            Assert.IsTrue(html.FirstNode() == head);
            Assert.IsTrue(html.LastNode() == body);
            Assert.IsTrue(head.NextNode() == body);
            Assert.IsTrue(body.PreviousNode() == head);
            }

        [TestMethod]
        public void Root() {
            SgmlDocument doc = new SgmlDocument();
            SElement html = new SElement("html", SgmlNodeType.Element);
            doc.Root.Add(html);

            SAttribute attr1 = new SAttribute("attr1", "1");
            SAttribute attr2 = new SAttribute("attr2", "2");

            html.Add(attr1);
            html.Add(attr2);

            Assert.IsTrue(doc.Root.Root() == doc.Root);
            Assert.IsTrue(html.Root() == doc.Root);

            SElement head = new SElement("head", SgmlNodeType.Element);
            html.Add(head);

            Assert.IsTrue(head.Root() == doc.Root);
            }

        [TestMethod]
        public void InnerText() {
            SgmlDocument doc = new SgmlDocument();
            SElement html = new SElement("html", SgmlNodeType.Element);
            doc.Root.Add(html);

            SElement head = new SElement("head", SgmlNodeType.Element);
            html.Add(head);

            SElement title = new SElement("title", SgmlNodeType.Element);
            head.Add(title);
            SElement titleText = new SElement(SName.Empty, SgmlNodeType.Text);
            titleText.Value = "Title";
            title.Add(titleText);

            SElement body = new SElement("body", SgmlNodeType.Element);
            html.Add(body);
            SElement bodyText = new SElement(SName.Empty, SgmlNodeType.Text);
            bodyText.Value = "Body text";
            body.Add(bodyText);

            string content = doc.ToString();
            string xml = doc.ToXml();

            string innerText = doc.Root.InnerText();
            Assert.IsTrue(innerText.Equals("TitleBody text"));
            innerText = html.InnerText();
            Assert.IsTrue(innerText.Equals("TitleBody text"));
            innerText = head.InnerText();
            Assert.IsTrue(innerText.Equals("Title"));
            innerText = body.InnerText();
            Assert.IsTrue(innerText.Equals("Body text"));
            }

        [TestMethod]
        public void Nodes() {
            SgmlDocument doc = new SgmlDocument();
            SElement html = new SElement("html", SgmlNodeType.Element);
            doc.Root.Add(html);
            SElement head = new SElement("head", SgmlNodeType.Element);
            html.Add(head);
            SElement title = new SElement("title", SgmlNodeType.Element);
            head.Add(title);

            SElement body = new SElement("body", SgmlNodeType.Element);
            body.Add(new SElement("div", SgmlNodeType.Element));
            body.Add(new SElement("div", SgmlNodeType.Element));
            body.Add(new SElement("div", SgmlNodeType.Element));
            body.Add(new SElement("div", SgmlNodeType.Element));

            html.Add(body);

            Assert.IsTrue(html.Nodes().Count() == 2);
            Assert.IsTrue(body.Nodes().Count() == 4);

            Assert.IsTrue(body.Nodes("div").Count() == 4);
            Assert.IsTrue(body.Nodes("div2").Count() == 0);
            }

        [TestMethod]
        public void Attributes() {
            SgmlDocument doc = new SgmlDocument();
            SElement html = new SElement("html", SgmlNodeType.Element);
            doc.Root.Add(html);

            Assert.IsTrue(html.Attributes().Count() == 0);

            SAttribute attribute1 = new SAttribute("xmlns", "http://www.engine.com.ua/namespaces");
            SAttribute attribute2 = new SAttribute("name", "attribute value");
            html.Add(attribute1);
            html.Add(attribute2);

            Assert.IsTrue(html.Attributes().Count() == 2);
            Assert.IsNotNull(html.Attribute("xmlns"));
            Assert.IsNotNull(html.Attribute("name"));
            Assert.IsNull(html.Attribute("noname"));

            InvalidOperationException ex = null;
            try {
                doc.Root.Add(new SElement("html", SgmlNodeType.EndElement));
                }
            catch (InvalidOperationException e) {
                Assert.IsNotNull(e.Message);
                Assert.IsFalse(string.IsNullOrWhiteSpace(e.Message));
                ex = e;
                }
            Assert.IsNotNull(ex);

            string content = doc.ToString();
            string xml = doc.ToXml();
            }
        }
    }
